/*
 * User: rant
 * Date: 21/12/2006
 *
 *
 */
package laMalinche.rete.nodes;

import laMalinche.rete.nodes.tailing.WorkingMemoryEvent;

import java.util.*;
import static java.lang.Boolean.*;

/**
 *
 */
public class MergerNode extends BasicRelevantListener {

	private Relevant leftNode;
	private Relevant rightNode;
	private boolean informingRelveancyChange;

	public Relevant getRightNode() {
		return rightNode;
	}

	@Override
	protected void setConditionMet(Boolean met) {
		Boolean oldConditionMet = isConditionMet();
		if (!compareBooleans(isConditionMet(), met)) {
            super.setConditionMet(met);
            boolean insideSetLoop = false;
            if (FALSE.equals(isConditionMet()) || FALSE.equals(oldConditionMet)) {
				final boolean becameTrue = !FALSE.equals(isConditionMet());
				if (isRelevant()) {
					if (informingRelveancyChange) {
						insideSetLoop = true;
					}
					informingRelveancyChange = true;
					informChangeRelevancy(becameTrue);
					informingRelveancyChange = false;
				}
			}
			if (!insideSetLoop && !compareBooleans(oldConditionMet, isConditionMet())) {
				adviseListeners(isConditionMet());
			}
		}
	}

	@Override
	public void addRelvantListener(BasicRelevantListener listener) {
		final boolean wasRelevant = isRelevant();
		super.addRelvantListener(listener);
		if (!wasRelevant && FALSE.equals(isConditionMet())) {
			informChangeRelevancy(FALSE);
		}
	}

	private Boolean calculateConditionMet() {
		final Boolean conditionMet;
		if (FALSE.equals(leftNode.isConditionMet()) || FALSE.equals(rightNode.isConditionMet())) {
			conditionMet = FALSE;
		} else if (leftNode.isConditionMet() == null || rightNode.isConditionMet() == null) {
			conditionMet = null;
		} else {
			conditionMet = true;
		}
		return conditionMet;
	}

	public ReteNode getLeftNode() {
		return leftNode;
	}

	public void workingMemoryChange(WorkingMemoryEvent event) {
		final Boolean conditionMet = calculateConditionMet();
		setConditionMet(conditionMet);
	}

	public void addLeftNode(Relevant node) {
        leftNode = node;
		if (rightNode != null) {
			final Boolean conditionMet = calculateConditionMet();
			setConditionMet(conditionMet);
		}
		((BasicRelevantListener) node).addRelvantListener(this);
	}

	public void addRightNode(Relevant node) {
        rightNode = node;
		if (leftNode != null) {
			final Boolean conditionMet = calculateConditionMet();
			setConditionMet(conditionMet);
		}
		((BasicRelevantListener) node).addRelvantListener(this);
	}

	@Override
	public void informChangeRelevancy(final boolean relevant) {
		List<Relevant> relevants = getInterestedInRelevant();
		for (Relevant relevantNode : relevants) {
			relevantNode.relveancyChanged(relevant);
		}
//		rightNode.relveancyChanged(relevant);
//		leftNode.relveancyChanged(relevant);
	}

	private List<Relevant> getInterestedInRelevant() {
		List<Relevant> result = new ArrayList<Relevant>();
		result.add(rightNode);
		result.add(leftNode);
		return result;
	}

	@Override
	public int hashCode() {
		return 3;
	}

	@Override
	public boolean equals(Object merger) {
		boolean result = false;
		if (merger instanceof MergerNode) {
			MergerNode mergerNode = (MergerNode) merger;
			result = (leftNode.equals(mergerNode.getRightNode()) || leftNode.equals(mergerNode.getLeftNode()))
					&&
					(rightNode.equals(mergerNode.getRightNode()) || rightNode.equals(mergerNode.getLeftNode()));
		}
		return result;
	}
}